package com.boot.controller;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.annotation.RateLimit;
import com.boot.config.TokenStore;
import com.boot.constants.StatusConstants;
import com.boot.dto.OperationLogDTO;
import com.boot.entity.Result;
import com.boot.entity.User;
import com.boot.exception.BusinessException;
import com.boot.service.IUserService;
import com.boot.service.LoginAttemptService;
import com.boot.utils.JwtUtil;
import com.boot.utils.SecurityUtils;
import com.boot.utils.UserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/user")
public class UserController {
    private static final Logger log = LoggerFactory.getLogger("OPERATION_LOG");

    @Resource
    private IUserService userService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private TokenStore tokenStore;

    @Resource
    private LoginAttemptService loginAttemptService;

    /**
     * 用户登录接口
     */
    @PostMapping("/login")
    @RateLimit(limit = 5, windowSec = 60)
    public Result<Map<String, String>> login(@Valid @RequestBody LoginRequest request, HttpServletRequest httpServletRequest) {
        String clientIp = getClientIp(httpServletRequest);
        String username = request.getUsername();
        LocalDateTime startTime = LocalDateTime.now();

        // 初始化日志 DTO
        OperationLogDTO logDTO = new OperationLogDTO();
        logDTO.setMethod("POST");
        logDTO.setUri("/user/login");
        logDTO.setIp(clientIp);
        logDTO.setRequestParams(Collections.singletonMap("username", username)); // 只记录用户名，密码已被脱敏
        logDTO.setTimestamp(startTime);

        // 1. 检查是否被锁定
        if (loginAttemptService.isBlocked(clientIp)) {
            logDTO.setStatus(401);
            logDTO.setResponseBody("登录失败：IP已被锁定");
            log.info(JSONUtil.toJsonStr(logDTO));

            return Result.fail("登录失败次数过多，该IP已被暂时锁定，请15分钟后重试");
        }

        // 2. 查用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User user = userService.getOne(wrapper);

        boolean passwordMatches = user != null && passwordEncoder.matches(request.getPassword(), user.getPassword());

        if (user == null || !passwordMatches) {
            loginAttemptService.loginFailed(clientIp);

            logDTO.setStatus(401);
            logDTO.setResponseBody("登录失败：用户名或密码错误");
            log.info(JSONUtil.toJsonStr(logDTO));

            return Result.fail("用户名或密码错误");
        }

        // 3. 检查用户状态
        if (!StatusConstants.UserStatus.ENABLED.equals(user.getStatus())) {
            loginAttemptService.loginFailed(clientIp);

            logDTO.setStatus(401);
            logDTO.setResponseBody("登录失败：账号已被禁用");
            log.info(JSONUtil.toJsonStr(logDTO));

            return Result.fail("账号已被禁用");
        }

        // 4. 登录成功 → 清除失败记录
        loginAttemptService.loginSuccess(clientIp);

        // 5. 生成 token...
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getId());
        claims.put("username", user.getUsername());

        String token = jwtUtil.generateToken(claims);
        tokenStore.saveToken(token, user.getId());

        Map<String, String> data = new HashMap<>();
        data.put("token", token);
        data.put("username", user.getUsername());
        data.put("userId", user.getId().toString());

        // ✅ 记录成功日志
        logDTO.setStatus(200);
        logDTO.setResponseBody("登录成功");
        logDTO.setTakeTime(System.currentTimeMillis() - startTime.atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli());
        log.info(JSONUtil.toJsonStr(logDTO));

        return Result.success(data);
    }

    // 辅助方法：获取客户端IP
    private String getClientIp(HttpServletRequest request) {
        String xff = request.getHeader("X-Forwarded-For");
        if (xff != null && !xff.isEmpty() && !"unknown".equalsIgnoreCase(xff)) {
            return xff.split(",")[0].trim();
        }
        String xri = request.getHeader("X-Real-IP");
        if (xri != null && !xri.isEmpty() && !"unknown".equalsIgnoreCase(xri)) {
            return xri.trim();
        }
        return request.getRemoteAddr();
    }

    /**
     * 用户登出接口
     */
    @RateLimit(limit = 5, windowSec = 60)
    @PostMapping("/logout")
    public Result<String> logout(@RequestHeader("Authorization") String authHeader) {
        String token = null;
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            token = authHeader.substring(7);
        }

        if (token != null && tokenStore.isValid(token)) {
            tokenStore.removeToken(token);
        }

        return Result.success("登出成功");
    }

    // 登录请求 DTO
    public static class LoginRequest {
        private String username;
        private String password;

        // getter/setter
        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    /**
     * 获取推荐专家列表（默认前10条，可带关键词搜索）
     */
    @RateLimit(limit = 50, windowSec = 60)
    @GetMapping("/experts")
    public Result<List<User>> getExperts(@RequestParam(required = false) String keyword, @RequestParam(defaultValue = "10") Integer limit) {
        try {
            Long currentUserId = SecurityUtils.requireCurrentUserId();

            // 校验并限制最大数量
            if (limit == null || limit <= 0 || limit > 50) {
                limit = 10;
            }

            // 创建 Page 对象，当前页为1，每页显示 limit 条
            Page<User> page = new Page<>(1, limit);

            QueryWrapper<User> wrapper = new QueryWrapper<>();

            // 排除当前用户
            wrapper.ne("id", currentUserId);

            // 用户状态为启用
            wrapper.eq("status", StatusConstants.UserStatus.ENABLED);
            // 模糊搜索用户名
            if (keyword != null && !keyword.trim().isEmpty()) {
                wrapper.like("username", keyword.trim());
            }
            // 排序：按创建时间降序
            wrapper.orderByDesc("created_at");

            // 只查必要字段
            wrapper.select("id", "username");

            // 执行分页查询
            Page<User> userPage = userService.page(page, wrapper);

            return Result.success(userPage.getRecords());
        } catch (IllegalArgumentException | SecurityException | IllegalStateException | BusinessException e) {
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.fail("系统错误");
        }
    }

    /**
     * token校验接口
     */
    @RateLimit(limit = 100, windowSec = 60)
    @PostMapping("/check")
    public Result<Boolean> check(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null) {
            return Result.success(false);
        }

        String token = null;
        if (authHeader.startsWith("Bearer ")) {
            token = authHeader.substring(7);
        }

        if (token != null && tokenStore.isValid(token)) {
            return Result.success(true);
        }

        return Result.success(false);
    }
}
